`include "defines.v"
module instrBuffer#(
  parameter DataW = 32,
  parameter Depth = 32
)(
  input clk,
  input rst_n,

  input flush,

  input  in_valid,
  output in_ready,
  // output almost_full,
  input [DataW-1:0] din,

  output out_valid,
  input  out_ready,
  output [DataW-1:0] dout
);

  reg [DataW-1:0] fifo_reg [0:Depth-1];
  reg [$clog2(Depth):0] wr_ptr;
  reg [$clog2(Depth):0] rd_ptr;
  wire full,empty;
  wire wen,ren;

  always@(posedge clk or negedge rst_n)
    if(~rst_n)
      wr_ptr <= 'd0;
    else if(flush)
      wr_ptr <= 'd0;
    else if((wen && ~full) || (wen && full && ren))
      wr_ptr <= wr_ptr + 1'b1;

  always@(posedge clk or negedge rst_n)
    if(~rst_n)
      rd_ptr <= 'd0;
    else if(flush)
      rd_ptr <= 'd0;
    else if((ren && ~empty) || (ren && wen && empty))
      rd_ptr <= rd_ptr + 1'b1;

  always@(posedge clk )
    if(wen && ~full)
      fifo_reg[wr_ptr[$clog2(Depth)-1:0]] <= din;
    else if(wen && full && ren)
      fifo_reg[wr_ptr[$clog2(Depth)-1:0]] <= din;
  
  assign dout = (wen && ren && empty) ? din : fifo_reg[rd_ptr[$clog2(Depth)-1:0]];

  assign full  = ( rd_ptr[$clog2(Depth)-1:0] == wr_ptr[$clog2(Depth)-1:0] ) && (rd_ptr[$clog2(Depth)] != wr_ptr[$clog2(Depth)]);
  // assign almost_full = ( rd_ptr[$clog2(Depth)-1:0] == (wr_ptr[$clog2(Depth)-1:0] + 1'b1) ) && (rd_ptr[$clog2(Depth)] != wr_ptr[$clog2(Depth)]);
  assign empty = rd_ptr == wr_ptr;
  assign wen   = in_valid;
  assign ren   = out_ready;
  assign in_ready  = ~full || (wen && full && ren);
  assign out_valid = ~empty || (ren && wen && empty);

endmodule